package com.hyl.aop.catcheaop;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.hyl.anno.catche.CGet;
import com.hyl.anno.catche.CPut;
import com.hyl.common.utils.RedisTools;
import com.hyl.myenum.cacheused.ElementChosen;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

/**
 * 自定义缓存的写法
 * @author HYL
 * @create 2017-06-20 上午9:37
 **/
@Component
@Aspect//申明这是一个切面
public class CatcheAop {

    @Autowired
    private RedisTools redisTools;

//    申明切点，就是所有的serviceimpl的所有方法
    @Pointcut("execution(* com.hyl.service.*.impl.*.*(..))")
    public void executeService(){

    }

    @Around("execution(* com.hyl.service.*.impl.*.*(..))")
    public Object doAroundAdvice(ProceedingJoinPoint proceedingJoinPoint){
        System.out.println("走缓存框架");
        Signature signature = proceedingJoinPoint.getSignature();//获得代理签名
        Object[] args = proceedingJoinPoint.getArgs();
        String paras = JSONArray.toJSONString(args);
        MethodSignature methodSignature = (MethodSignature) signature;
        Class clazz = methodSignature.getReturnType();
        Method method = methodSignature.getMethod();
        String name = method.getName();
        String clazzName = signature.getDeclaringType().getName();
        StringBuilder sb=new StringBuilder();
        String key = sb.append(clazzName).append("/").append(name).append("/").append(paras).toString();
        /**
         * 下面的逻辑：如果有注解cput，那么就把参数保存到缓存中或者是更新
         * 如果是注解cget ,那么他的逻辑就是先从换从中获取，如果没有获取到就给予返回值
         */
        if (method.isAnnotationPresent(CPut.class)) {//如果是要把内容保存到redis中
            try {
//            获得方法的返回值
                Object obj = proceedingJoinPoint.proceed();
//          把返回值存入到缓存中，key为这个方法的所有的方法参数等相关信息
                String value = JSONObject.toJSONString(obj);
                redisTools.setByTime(key,value,2*60*60L);
                return obj;
            } catch (Throwable throwable) {
                throwable.printStackTrace();
            }
        }
        if (method.isAnnotationPresent(CGet.class)) {
            //获取注解里面的值
            String value = redisTools.getValue(key);
            Object o = JSON.parseObject(value, clazz);
            ElementChosen elementChosens = method.getAnnotation(CGet.class).value();
            if (elementChosens.equals(ElementChosen.CACHEONLY)){
                System.out.println("无论如何都从缓存中获取值并返回");
                return o;
            }else {
                if (value != null) {
                    System.out.println("只有换从中有值才从缓存中获取并返回");
                    return o;
                }else {
                    System.out.println("第一次进来没有缓存，把返回值丢进缓存");
                    try {
//            获得方法的返回值
                        Object obj = proceedingJoinPoint.proceed();
//          把返回值存入到缓存中，key为这个方法的所有的方法参数等相关信息
                        redisTools.setByTime(key,JSONObject.toJSONString(obj),2*60*60L);
                        return obj;
                    } catch (Throwable throwable) {
                        throwable.printStackTrace();
                    }
                }
            }


        }

        return null;
    }
}
